#include "Scene.h"

#include "Scene/NativeScript.h"

#include "Core/GlobalContext.h"

#include "Platform/OpenGL/OpenGLBase.h"

namespace SE
{
	Entity Scene::createEntity(const String& name)
	{
		return createEntity(GUID(), name);
	}

	Entity Scene::createEntity(const GUID& guid, const String& name)
	{
		Entity entity = { this, mRegistry.create() };
		entity.addComponent<TagComponent>(name);
		entity.addComponent<GUIDComponent>(guid);
		entity.addComponent<TransformComponent>();
		mEntityMap[guid] = entity;
		
		return entity;
	}

	void Scene::destroyEntity(Entity& entity)
	{
		mEntityMap.erase(entity.getComponent<GUIDComponent>().guid);
		mRegistry.destroy(entity);
	}

	void Scene::onCompute(const Double deltaMilliseconds)
	{
		// Update scriptable components.
		{
			auto view = mRegistry.view<ScriptableComponent>();
			for (auto entity : view)
			{
				auto& scriptableComponent = view.get<ScriptableComponent>(entity);
				scriptableComponent.script->onUpdate({ this, entity }, deltaMilliseconds);
			}
		}
	}

	void Scene::onRender(const Double deltaMilliseconds)
	{
		Entity activedCameraEntity;
		CameraData activedCameraData;
		// Find actived camera.
		{
			auto view = mRegistry.view<TransformComponent, CameraComponent>();
			for (auto entity : view)
			{
				auto [transformComponent, cameraComponent] = view.get<TransformComponent, CameraComponent>(entity);
				if (cameraComponent.actived)
				{
					activedCameraEntity = { this, entity };
					activedCameraData = { transformComponent.position, glm::inverse(transformComponent.getTransform()), cameraComponent.getProjection()};
				}
			}
		}

		// No render pass with no actived camera.
		if (!activedCameraEntity)
		{
			return;
		}

		RenderAPI::BindToBackground();
		RenderAPI::SetClearColor({ 0.2f, 0.3f, 0.4f, 1.0f });
		RenderAPI::Clear();

		RenderAPI::BeginScene(activedCameraData);

		// Draw meshs.
		{
			auto view = mRegistry.view<TransformComponent, MeshRendererComponent>();
			for (auto entity : view)
			{
				auto [transformComponent, meshRendererComponent] = view.get<TransformComponent, MeshRendererComponent>(entity);

				if (meshRendererComponent.meshInstance)
				{
					meshRendererComponent.meshInstance->onRender(transformComponent.getTransform());
				}
			}
		}

		RenderAPI::EndScene();
		
		RenderAPI::BindToForeground();
	}
} // !namespace SE